﻿using System.Security.Cryptography;
using System.Text;

namespace Sage.Encryption
{

    /// <summary>
    /// 提供基于AES算法的加密服务实现
    /// </summary>
    public class AesEncryptionService : IEncryptionService, IDisposable
    {
        private readonly byte[] _key;
        private readonly byte[] _iv;
        private bool _disposed;

        /// <summary>
        /// 使用指定的密钥和初始化向量创建AES加密服务实例
        /// </summary>
        public AesEncryptionService(byte[] key, byte[] iv)
        {
            ArgumentNullException.ThrowIfNull(key);
            ArgumentNullException.ThrowIfNull(iv);

            if (key.Length is not (16 or 24 or 32))
                throw new ArgumentException("密钥长度必须为16、24或32字节", nameof(key));

            if (iv.Length != 16)
                throw new ArgumentException("初始化向量长度必须为16字节", nameof(iv));

            _key = key;
            _iv = iv;
        }

        /// <summary>
        /// 使用密码和盐值创建AES加密服务实例
        /// </summary>
        public AesEncryptionService(string password, string salt, int iterations = 10000)
        {
            ArgumentException.ThrowIfNullOrEmpty(password);
            ArgumentException.ThrowIfNullOrEmpty(salt);

            if (iterations < 1)
                throw new ArgumentException("迭代次数必须大于0", nameof(iterations));

            byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
            byte[] derivedBytes = new byte[48]; // 32 + 16

            // 使用 Span 重载直接写入目标数组
            Rfc2898DeriveBytes.Pbkdf2(
                password,
                saltBytes,
                derivedBytes.AsSpan(),
                iterations,
                HashAlgorithmName.SHA256
            );

            _key = derivedBytes[..32];
            _iv = derivedBytes[32..];
        }


        /// <summary>
        /// 随机生成密钥和IV
        /// </summary>
        public static (byte[] Key, byte[] IV) GenerateRandomKeyAndIv()
        {
            using var aes = Aes.Create();
            aes.GenerateKey();
            aes.GenerateIV();
            return (aes.Key, aes.IV);
        }

        /// <inheritdoc/>
        public byte[] Encrypt(string plainText)
        {
            ArgumentException.ThrowIfNullOrEmpty(plainText);
            return Encrypt(Encoding.UTF8.GetBytes(plainText));
        }

        /// <inheritdoc/>
        public byte[] Encrypt(byte[] plainBytes)
        {
            ArgumentNullException.ThrowIfNull(plainBytes);
            ObjectDisposedException.ThrowIf(_disposed, this);

            using var aes = Aes.Create();
            aes.Key = _key;
            aes.IV = _iv;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            using var encryptor = aes.CreateEncryptor();
            using var memoryStream = new MemoryStream();
            using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

            cryptoStream.Write(plainBytes);
            cryptoStream.FlushFinalBlock();
            return memoryStream.ToArray();
        }

        /// <inheritdoc/>
        public async Task<byte[]> EncryptAsync(byte[] plainBytes)
        {
            ArgumentNullException.ThrowIfNull(plainBytes);
            ObjectDisposedException.ThrowIf(_disposed, this);

            using var aes = Aes.Create();
            aes.Key = _key;
            aes.IV = _iv;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            using var encryptor = aes.CreateEncryptor();
            using var memoryStream = new MemoryStream();
            using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

            await cryptoStream.WriteAsync(plainBytes);
            await cryptoStream.FlushFinalBlockAsync();
            return memoryStream.ToArray();
        }

        /// <inheritdoc/>
        public string DecryptToString(byte[] cipherBytes)
        {
            ArgumentNullException.ThrowIfNull(cipherBytes);
            return Encoding.UTF8.GetString(Decrypt(cipherBytes));
        }

        /// <inheritdoc/>
        public byte[] Decrypt(byte[] cipherBytes)
        {
            ArgumentNullException.ThrowIfNull(cipherBytes);
            ObjectDisposedException.ThrowIf(_disposed, this);

            using var aes = Aes.Create();
            aes.Key = _key;
            aes.IV = _iv;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            using var decryptor = aes.CreateDecryptor();
            using var memoryStream = new MemoryStream(cipherBytes);
            using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            using var resultStream = new MemoryStream();

            cryptoStream.CopyTo(resultStream);
            return resultStream.ToArray();
        }

        /// <inheritdoc/>
        public async Task<byte[]> DecryptAsync(byte[] cipherBytes)
        {
            ArgumentNullException.ThrowIfNull(cipherBytes);
            ObjectDisposedException.ThrowIf(_disposed, this);

            using var aes = Aes.Create();
            aes.Key = _key;
            aes.IV = _iv;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            using var decryptor = aes.CreateDecryptor();
            using var memoryStream = new MemoryStream(cipherBytes);
            using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            using var resultStream = new MemoryStream();

            await cryptoStream.CopyToAsync(resultStream);
            return resultStream.ToArray();
        }

        /// <summary>
        /// 释放资源并安全清除敏感数据
        /// </summary>
        public void Dispose()
        {
            if (!_disposed)
            {
                // 清除敏感数据
                Array.Clear(_key);
                Array.Clear(_iv);
                _disposed = true;
                GC.SuppressFinalize(this);
            }
        }
    }

}
